home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Visual Cafe 3
/
Visual Cafe 3.ISO
/
Vcafe
/
JFC.bin
/
TableView.java
< prev
next >
Wrap
Text File
|
1998-06-30
|
11KB
|
399 lines
/*
* @(#)TableView.java 1.7 98/04/09
*
* Copyright (c) 1997 Sun Microsystems, Inc. All Rights Reserved.
*
* This software is the confidential and proprietary information of Sun
* Microsystems, Inc. ("Confidential Information"). You shall not
* disclose such Confidential Information and shall use it only in
* accordance with the terms of the license agreement you entered into
* with Sun.
*
* SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
* SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
* IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
* SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
* THIS SOFTWARE OR ITS DERIVATIVES.
*
*/
package com.sun.java.swing.text;
import java.awt.*;
/**
* <p>
* Implements View interface for a table, that is composed of a
* specific element structure where the child elements of the element
* this view is responsible for represent rows and the child
* elements of the row elements are cells. The cell elements can
* have an arbitrary element structure under them.
* <pre><code>
* TABLE
* ROW
* CELL
* CELL
* ROW
* CELL
* CELL
* </code></pre>
* <p>
* This is implemented as a hierarchy of boxes, the table itself
* is a vertical box, the rows are horizontal boxes, and the cells
* are vertical boxes. The cells are allowed to span multiple
* columns and rows. By default, the table can be thought of as
* being formed over a grid, where cells can request to span more
* than one grid cell. The default horizontal span of table cells
* will be based upon this grid, but can be changed by reimplementing
* the requested span of the cell.
*
* @author Timothy Prinzing
* @version 1.7 04/09/98
* @see View
*/
public class TableView extends BoxView {
/**
* Constructs a TableView for the given element.
*
* @param elem the element that this view is responsible for
*/
public TableView(Element elem) {
super(elem, View.Y_AXIS);
}
/**
* Creates a new table row.
*
* @param elem an element
* @return the row
*/
protected TableRow createTableRow(Element elem) {
return new TableRow(elem);
}
/**
* Creates a new table cell.
*
* @param elem an element
* @return the cell
*/
protected TableCell createTableCell(Element elem) {
return new TableCell(elem);
}
/**
* Fetches the span (width) of the given column.
* This is used by the nested cells to query the
* sizes of grid locations outside of themselves.
*/
int getColumnSpan(int col) {
return colWidths[col];
}
/**
* Fetches the span (height) of the given row.
* This is used by the nested cells to query the
* sizes of grid locations outside of themselves.
*/
int getRowSpan(int row) {
View v = getView(row);
return (int) v.getPreferredSpan(Y_AXIS);
}
/**
* Loads all of the children to initialize the view.
* This is called by the <code>setParent</code> method.
* This is reimplemented to build rows using the
* <code>createTableRow</code> method and then
* proxy cell entries for each of the cells that
* span multiple columns or rows, substantially
* reducing the complexity of the layout calculations.
*
* @param f the view factory
*/
protected void loadChildren(ViewFactory f) {
Element e = getElement();
int n = e.getElementCount();
if (n > 0) {
View[] added = new View[n];
for (int i = 0; i < n; i++) {
added[i] = createTableRow(e.getElement(i));
}
replace(0, 0, added);
}
// fill in the proxy cells
for (int row = 0; row < n; row++) {
View rv = getView(row);
for (int col = 0; col < rv.getViewCount(); col++) {
View cv = rv.getView(col);
if (cv instanceof TableCell) {
TableCell cell = (TableCell) cv;
if ((cell.getColumnCount() > 1) ||
(cell.getRowCount() > 1)) {
// fill in the proxy entries for this cell
for (int i = row; i < row + cell.getRowCount(); row++) {
for (int j = col; j < col + cell.getColumnCount(); j++) {
if (i != 0 && j != 0) {
addProxy(i, j, cell);
}
}
}
}
}
}
}
calculateGrid();
}
void calculateGrid() {
int ncols = 0;
int nrows = getViewCount();
for (int i = 0; i < nrows; i++) {
View row = getView(i);
ncols = Math.max(ncols, row.getViewCount());
}
colWidths = new int[ncols];
for (int i = 0; i < nrows; i++) {
View row = getView(i);
ncols = row.getViewCount();
for (int j = 0; j < ncols; j++) {
TableCell cell = (TableCell) row.getView(j);
colWidths[j] = Math.max(cell.getPreferredColumnSpan(),
colWidths[j]);
}
row.preferenceChanged(null, true, false);
}
}
/**
* Adds a cell to fill in for another cells overflow. The proxy cells
* are simply for simplification of layout and have no useful semantics.
*/
void addProxy(int row, int col, TableCell host) {
TableRow rv = (TableRow) getView(row);
rv.insert(col, new ProxyCell(host));
}
/**
* Performs layout of the children. The size is the
* area inside of the insets. The table layout is mostly
* the default behavior of the boxes, where the requests
* made by the cells for their width is based upon
* a common set of values held in the table. The table
* itself calculates these values before the layout
* proceeds and these values get used by the cells.
*
* @param width the width >= 0
* @param height the height >= 0
*/
protected void layout(int width, int height) {
calculateGrid();
super.layout(width, height);
}
// ---- View methods ----------------------------------------------------
int[] colWidths;
/**
* View of a row in a table.
*/
public class TableRow extends BoxView {
/**
* Constructs a TableView for the given element.
*
* @param elem the element that this view is responsible for
*/
public TableRow(Element elem) {
super(elem, View.X_AXIS);
}
/**
* Loads all of the children to initialize the view.
* This is called by the <code>setParent</code> method.
* This is reimplemented to build cells using the
* <code>createTableCell</code> method.
*
* @param f the view factory
*/
protected void loadChildren(ViewFactory f) {
Element e = getElement();
int n = e.getElementCount();
if (n > 0) {
View[] added = new View[n];
for (int i = 0; i < n; i++) {
added[i] = createTableCell(e.getElement(i));
}
replace(0, 0, added);
}
}
}
/**
* View of a cell in a table
*/
public class TableCell extends BoxView {
/**
* Constructs a TableCell for the given element.
*
* @param elem the element that this view is responsible for
*/
public TableCell(Element elem) {
super(elem, View.Y_AXIS);
}
/**
* Gets the number of columns this cell spans (e.g. the
* grid width).
*
* @return the number of columns
*/
public int getColumnCount() {
return 1;
}
/**
* Gets the number of rows this cell spans (that is, the
* grid height).
*
* @return the number of rows
*/
public int getRowCount() {
return 1;
}
/**
* Sets the grid location.
*
* @param row the row >= 0
* @param col the column >= 0
*/
public void setGridLocation(int row, int col) {
this.row = row;
this.col = col;
}
/**
* Gets the preferred span for the column occupied. This
* is basically the host's desired column span.
* The host divides its desired across the number
* of grid points.
*
* @return the span
*/
public int getPreferredColumnSpan() {
return ((int) super.getPreferredSpan(X_AXIS)) / getColumnCount();
}
// --- View methods -----------------------------
/**
* Renders using the given rendering surface and area on that
* surface. This is implemented to delegate to the superclass
* after adjusting the allocation if needed because the
* cell spans multiple grid points (eg. muliple columns
* and/or rows).
*
* @param g the rendering surface to use
* @param allocation the allocated region to render into
* @see View#paint
*/
public void paint(Graphics g, Shape allocation) {
Rectangle alloc = allocation.getBounds();
int nrows = getRowCount();
int ncols = getColumnCount();
if (nrows > 1 || ncols > 1) {
// adjust the allocation
for (int i = 1; i < ncols; i++) {
alloc.width += getColumnSpan(col + i);
}
for (int i = 1; i < nrows; i++) {
alloc.height += getRowSpan(row + i);
}
}
}
/**
* Determines the preferred span for this view along an
* axis. For the x axis, this is implemented to return
* the column width for the grid location that this cell
* lives at. This is the method that is effectively
* controlling the layout of the table. Cells can be
* independantly altered by re-implementing this method.
*
* @param axis may be either View.X_AXIS or View.Y_AXIS
* @returns the span the view would like to be rendered into.
* Typically the view is told to render into the span
* that is returned, although there is no guarantee.
* The parent may choose to resize or break the view.
*/
public float getPreferredSpan(int axis) {
switch (axis) {
case View.X_AXIS:
return getColumnSpan(col);
default:
return super.getPreferredSpan(axis);
}
}
int row;
int col;
}
/**
* A special table cell that simply occupies space in the
* table at a grid location to make calculations easier to
* deal with.
*/
class ProxyCell extends TableCell {
ProxyCell(TableCell host) {
super(host.getElement());
}
/**
* Loads all of the children to initialize the view.
* This is called by the <code>setParent</code> method.
* This is reimplemented to do nothing... proxy cells
* are just a place holder.
*
* @param f the view factory
*/
protected void loadChildren(ViewFactory f) {
}
/**
* Gets the preferred span for the column occupied. This
* is basically the host's desired column span.
* The host divides its desired across the number
* of grid points.
*/
public int getPreferredColumnSpan() {
return host.getPreferredColumnSpan();
}
/**
* Renders using the given rendering surface and area on that
* surface. This is implemented to do nothing as proxy cells
* are supposed to be invisible place holders.
*
* @param g the rendering surface to use
* @param allocation the allocated region to render into
* @see View#paint
*/
public void paint(Graphics g, Shape allocation) {
}
TableCell host;
}
}